package comp6231.project.replica.dimitri;
/**
 * Distributed Retail System
 * Oct 6, 2012 
 */


import java.io.EOFException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * @author dimitri.tiago
 *
 */
public class CustomerDatabase
{
	private String store;

	private int numOfReaders;
	private Semaphore writerSemaphore;
	private Semaphore readerSemaphore;

	public CustomerDatabase(String store)
	{
		this.store = store;
		createFile(store); // create customer db file

		numOfReaders = 0;
		writerSemaphore = new Semaphore(1);
		readerSemaphore = new Semaphore(1);
	}

	private void createFile(String store)
	{
		RandomAccessFile file = null;

		try
		{
			String filename = String.format("%s.dat", store);
			file = new RandomAccessFile(filename, "rw");

			System.out.printf("Initialized customer database file: %s\n", filename);
		}
		catch(IOException ioe)
		{
			ioe.printStackTrace();
		}
		finally
		{
			try
			{
				if (file != null)
				{
					file.close();
				}
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}

	public void insertRecord(String customerID, int itemID, int numberOfItems)
	{
		// insert record in new thread (this maximizes concurrency)
		RandomAccessCustomerRecord newRecord = new RandomAccessCustomerRecord(customerID, itemID, numberOfItems);
		String filename = String.format("%s.dat", store);

		CustomerDatabaseInsert databaseInsert = new CustomerDatabaseInsert(writerSemaphore, newRecord, filename);
		Thread insertOperation = new Thread(databaseInsert);
		insertOperation.start();
	}

	public void updateRecord(String customerID, int itemID, int numberOfItems)
	{
		// insert record in new thread (this maximizes concurrency)
		RandomAccessCustomerRecord updateRecord = new RandomAccessCustomerRecord(customerID, itemID, numberOfItems);
		String filename 		        = String.format("%s.dat", store);

		CustomerDatabaseUpdate databaseUpdate = new CustomerDatabaseUpdate(writerSemaphore, updateRecord, filename);
		Thread updateOperation = new Thread(databaseUpdate);
		updateOperation.start();
	}

	public String[] selectRecord(String customerID, int itemID)
	{
		readerSemaphore.Wait();	  // entering readers critical section
		numOfReaders++;
		if (numOfReaders == 1)
		{
			writerSemaphore.Wait();
		}
		readerSemaphore.Signal(); // leaving readers critical section

		// entering critical section
		String [] recordFound = null;

		RandomAccessCustomerRecord selectRecord   = new RandomAccessCustomerRecord(customerID, itemID, 0);
		RandomAccessCustomerRecord recordSelected = selectRecord(selectRecord);

		if ( ! (recordSelected.getCustomerID().equalsIgnoreCase("")) )
		{	    
			recordFound    = new String[3];
			recordFound[0] = recordSelected.getCustomerID();
			recordFound[1] = String.format("%d", recordSelected.getItemID());
			recordFound[2] = String.format("%d", recordSelected.getNumberOfItems());
		}
		// leaving critical section

		readerSemaphore.Wait();   // entering readers critical section
		numOfReaders--;
		if (numOfReaders == 0)
		{
			writerSemaphore.Signal();
		}
		readerSemaphore.Signal(); // leaving readers critical section

		return recordFound;
	}

	public ArrayList<RandomAccessCustomerRecord> exportRecords()
	{
		ArrayList<RandomAccessCustomerRecord> recordsExport = new ArrayList<RandomAccessCustomerRecord>(); 

		try
		{
			String filename 	  = String.format("%s.dat", store);
			RandomAccessFile file = new RandomAccessFile(filename, "r");

			long fileSize = file.length();
			int read	  = 0;
			while (read <= fileSize)
			{
				RandomAccessCustomerRecord record = new RandomAccessCustomerRecord();
				record.read(file);
				recordsExport.add(record);
				read += 18;
			}
			
			file.close();
		} 
		catch (EOFException eofe )
		{
			// empty database file
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		return recordsExport;
	}
	
	private RandomAccessCustomerRecord selectRecord(RandomAccessCustomerRecord selectRecord)
	{
		RandomAccessCustomerRecord record = new RandomAccessCustomerRecord();

		try
		{
			String filename 	  = String.format("%s.dat", store);
			RandomAccessFile file = new RandomAccessFile(filename, "r");
			String customerID	  = selectRecord.getCustomerID();
			int itemID		  = selectRecord.getItemID();

			while ( ! ((record.getCustomerID().equalsIgnoreCase(customerID)) && (record.getItemID() == itemID)) )
			{
				record.read(file);
			}
			
			file.close();
		} 
		catch (EOFException eofe )
		{
			// record not found. return empty record
			record = new RandomAccessCustomerRecord();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		return record;
	}
	
	public void importRecords(ArrayList<RandomAccessCustomerRecord> records)
	{
		try
		{
			String filename 	  = String.format("%s.dat", store);
			RandomAccessFile file = new RandomAccessFile(filename, "rw");
			file.setLength(0);	// truncate file to ensure clean database

			// write records to database file
			for (RandomAccessCustomerRecord record : records)
			{
				long appendPosition = file.length();
				file.seek(appendPosition);
				record.write(file);
			}
		
			file.close(); // close file

		} 
		catch (EOFException eofe )
		{
			// empty database file
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}